﻿using System;
using BasicFramework.Entities;
using BasicFramework.Enums;
using BasicFramework.Factory;
using BasicFramework.Helper;

namespace BasicFramework.Scenes
{
    public class Scene : IScene, IDisposable
    {
        #region Fields

        private Boolean disposed;
        private EntityFactory entityFactory;
        private EntityManager manager;
        private SceneState state;
        private string name;
        private Guid guid;
        #endregion

        #region Properties


        public EntityFactory EntityFactory
        {
            get { return entityFactory; }
        }

        public EntityManager Manager
        {
            get { return manager; }
        }

        /// <summary>
        /// Returns the Name of the scene
        /// </summary>
        public string Name
        {
            get { return this.name; }
        }

        /// <summary>
        /// Returns the GuID of the Scene.
        /// </summary>
        public Guid GUID
        {
            get { return this.guid; }
        }

        public SceneState State
        {
            get { return state; }
            internal set
            {
                if (value != this.state)
                {
                    this.state = value;
                    this.OnSceneStateChanged();
                }
            }
        }

        #endregion

        #region Constructors

        public Scene(string name, Guid guid)
        {
            this.name = name;
            this.guid = guid;

            this.manager = new EntityManager();
            this.entityFactory = new EntityFactory(this.manager);
        }

        public Scene(string name)
        {
            this.name = name;
            this.guid = Guid.NewGuid();

            this.manager = new EntityManager();
            this.entityFactory = new EntityFactory(this.manager);
        }


        #endregion

        #region Disposing

        ~Scene()
        {
            Dispose(false);
        }

        protected virtual void Dispose(Boolean disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                    // Dispose managed resources.
                    this.manager.Dispose();
                }

                // Release unmanaged resources. If disposing is false, 
                // only the following code is executed.

            }
            disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        #endregion


        #region Events

        public event EventHandler<EventArgs> SceneStateChanged;

        #endregion

        #region Methods

        /// <summary>
        /// Initialized is called after the Scene was added to the Scene Manager.
        /// </summary>
        public virtual void Initialize()
        {
        }

        /// <summary>
        /// Start is called after the State of the Scene is set to Running.
        /// </summary>
        public virtual void Start()
        {
            
            this.manager.Start();
            this.manager.LoadResources(true);
        }

        /// <summary>
        /// Stop is called after the State of the Scene is set to Stopped
        /// </summary>
        public virtual void Stop()
        {
            this.manager.UnloadResources(true);
            foreach (IEntity entity in manager)
            {
                entity.Enabled = false;
            }
        }

        /// <summary>
        /// Paused is called after the State of the Scene is set to Paused.
        /// </summary>
        public virtual void Paused()
        {
            this.manager.UnloadResources(true);
        }

        /// <summary>
        /// Resume is called after the State of the Scene is set from Paused to Running.
        /// </summary>
        public virtual void Resume()
        {
            this.manager.LoadResources(true);
        }

        /// <summary>
        /// Update Method, is called for every Frame
        /// </summary>
        public virtual void Update(float frame)
        {
            // Update Manager
            this.Manager.Update(frame);
        }

        /// <summary>
        /// Draw Method, is called for every Frame
        /// </summary>
        internal void Draw(float frame)
        {
            // Draw Manager 
            this.Manager.Draw(frame);
        }

        public virtual void OnSceneStateChanged()
        {
            Logger.Info("SceneState of scene " + this.Name + " set to " + this.State);
            if (this.SceneStateChanged != null)
            {
                this.SceneStateChanged(this, EventArgs.Empty);
            }
        }


        #endregion


    }
}
